This chapter connects GGUF quantization labels to concrete local behavior: file size, served metadata, and short deterministic completions. The examples use the Qwen 3.5 4B Q4 file because it leaves room for KV cache and repeated tests on a 12 GB GPU.
with llama_server(QWEN_Q4) as (base_url, command, mode): model_response = requests.get(f"{base_url}/v1/models", timeout=10).json() model_row = model_response["data"][0] metadata = model_row.get("meta") or model_row.get("metadata") or {} selected = {"id": model_row.get("id"),"file_type": metadata.get("general.file_type") or metadata.get("ftype"),"parameters": metadata.get("general.parameter_count") or metadata.get("n_params"),"context": metadata.get("llama.context_length") or metadata.get("n_ctx"),"embedding_length": metadata.get("llama.embedding_length") or metadata.get("n_embd"), }print("Server command:")print(" ".join(command)) pd.DataFrame([selected])
prompts = ["Q: In one sentence, what does quantization buy us for local LLMs?\nA:","Q: Name one risk of using an overly aggressive quantization.\nA:","Q: Why is KV cache memory still important after quantizing weights?\nA:",]rows = []with llama_server(QWEN_Q4) as (base_url, _, mode):for prompt in prompts: start = time.perf_counter() response = requests.post(f"{base_url}/completion", json={"prompt": prompt,"n_predict": 64,"temperature": 0,"stop": ["\nQ:"], }, timeout=90, ) elapsed = time.perf_counter() - start response.raise_for_status() payload = response.json() timings = payload.get("timings", {}) rows.append({"prompt": prompt.split("\n")[0],"answer": payload.get("content", "").strip(),"elapsed_s": round(elapsed, 2),"predicted_tokens": timings.get("predicted_n"),"predicted_tokens_per_s": round(timings.get("predicted_per_second", 0.0), 2), })inference_results = pd.DataFrame(rows)inference_results
server_mode: cpu_only
prompt
answer
elapsed_s
predicted_tokens
predicted_tokens_per_s
0
Q: In one sentence, what does quantization buy us for local LLMs?
Quantization reduces the model size and memory footprint, enabling efficient inference on devices with limited resou...
4.91
22
5.92
1
Q: Name one risk of using an overly aggressive quantization.
<think>\n\n</think>\n\nOne significant risk of using an overly aggressive quantization is **catastrophic performance...
11.70
64
5.97
2
Q: Why is KV cache memory still important after quantizing weights?
Because quantizing weights only reduces the memory footprint of the model parameters, but the KV cache is still need...
6.60
32
5.82
bench_command = [str(BENCH),"-m", str(QWEN_Q4),"-ngl", "all","-fa", "1","-c", "2048","-n", "32",]try: bench = subprocess.run(bench_command, capture_output=True, text=True, timeout=45)print(f"llama-bench return code: {bench.returncode}") text = (bench.stdout or bench.stderr).strip()print("\n".join(text.splitlines()[:20]))except subprocess.TimeoutExpired:print("llama-bench did not finish within the timeout.")
The served Q4 model is small enough to run repeated deterministic requests comfortably. The benchmark command is included as a stack diagnostic: if it fails while llama-server works, the immediate problem is the benchmark binary or runtime linkage rather than model availability.